#include "sPHENIX_RootManager.h"
 
#include <TParticle.h>
#include <TObjArray.h>
#include "TClonesArray.h"
#include "TROOT.h"
#include "TPluginManager.h"
#include "TApplication.h"
#include "TSystem.h"
#include "TH1.h"
#include "TH2.h"
#include "TPad.h"
#include "TCanvas.h"
#include "TFile.h"
#include "TF1.h"
#include "TH2D.h"
#include "TH3D.h"
#include "TFormula.h"
#include "TString.h"
#include "TPaveLabel.h"
#include "TStyle.h"

#include <strings.h>
#include <iostream>  // I/O 
#include <fstream>   // file I/O
#include <vector>
#include <map>
#include "sPHENIX_CalorimeterHit.h"

using namespace std;

/// \cond CLASSIMP
ClassImp(sPHENIX_RootManager)
/// \endcond
 
sPHENIX_RootManager* sPHENIX_RootManager::gInstance = 0;
 
//_____________________________________________________________________________
sPHENIX_RootManager::sPHENIX_RootManager(const char* projectName, 
					 FileMode fileMode)
  : TObject(),
    count(0)
{
  /// Standard constructor
  /// \param projectName  The project name (passed as the Root tree name)
  /// \param fileMode     Option for opening Root file (read or write mode)

  if (gInstance) {
    Fatal("sPHENIX_RootManager", "Singleton instance already exists.");
    return;
  }  
 
  TString fileName(projectName);
  fileName += ".root";
 
  TString treeTitle(projectName);
  treeTitle += " tree";
 
  switch (fileMode) {
  case kRead:
    File = new TFile(fileName);
    Tree = (TTree*) File->Get(projectName);
    break;
       
  case kWrite:  
    File = new TFile(fileName, "recreate");
    Tree = new TTree(projectName, treeTitle);
    ;;  
  }
}

//_____________________________________________________________________________
sPHENIX_RootManager::sPHENIX_RootManager()
  : TObject(),
    File(0),
    Tree(0)
{
  /// Default constructor
 
  if (gInstance) {
    Fatal("sPHENIX_RootManager", "Singleton instance already exists.");
    return;
  }  
 
  gInstance = this;
}
 
//_____________________________________________________________________________
sPHENIX_RootManager::~sPHENIX_RootManager() 
{
  /// Destructor
 
  delete  Tree->GetCurrentFile();
  gInstance = 0;
}
 
//
// static methods
//
 
//_____________________________________________________________________________
sPHENIX_RootManager* sPHENIX_RootManager::Instance()
{
  /// \return The singleton instance.
 
  return gInstance;
}  
 
//
// public methods
//
 
//_____________________________________________________________________________
void  sPHENIX_RootManager::Register(const char* name, const char* className, 
				    void* objAddress)
{
  /// Create a branch and associates it with the given address.
  /// \param name       The branch name
  /// \param className  The class name of the object
  /// \param objAddress The object address
 
  if (!Tree->GetBranch(name)) 
    Tree->Branch(name, className, objAddress);
  else  
    Tree->GetBranch(name)->SetAddress(objAddress);


}
 
//_____________________________________________________________________________
void  sPHENIX_RootManager::Fill()
{
  /// Fill the Root tree.
 
  Tree->Fill();
}  

//_____________________________________________________________________________
void sPHENIX_RootManager:: WriteAll()
{
  /// Write the Root tree in the file.

  TFile* file =  Tree->GetCurrentFile();
  file->Write();
  file->Close();
}  

//_____________________________________________________________________________
void  sPHENIX_RootManager::ReadEvent(Int_t i)
{
  /// Read the event data for \em i -th event for all connected branches.
  /// \param i  The event to be read

  Tree->GetEntry(i);
}

//_____________________________________________________________________________
void sPHENIX_RootManager::InitializeHistograms() 
{

  c2 = new TCanvas("plots", "plots", 700,1000);
  c2->Divide(2,3);
  c2->Draw();

  Path = gDirectory->GetPath();
  gInstance = this;

  /// Histograms
  hEtotTowerEMCal = (TH2D *)gROOT->FindObject("hEtotTowerEMCal");
  if (hEtotTowerEMCal) hEtotTowerEMCal->Reset();
  else
    hEtotTowerEMCal = new TH2D("hEtotTowerEMCal",
			       "hEtotTowerEMCal", 
			       Detector->GetEMCalNofTowersAxis(), 
			       0,
			       Detector->GetEMCalNofTowersAxis(),
			       Detector->GetEMCalNofTowersAxis(),
			       0,
			       Detector->GetEMCalNofTowersAxis());

  hNumberEventsByEnergyEMCal = (TH1D *)gROOT->FindObject("hNumberEventsByEnergyEMCal");
  if (hNumberEventsByEnergyEMCal) hNumberEventsByEnergyEMCal->Reset();
  else
    hNumberEventsByEnergyEMCal = new TH1D("hNumberEventsByEnergyEMCal",
					  "hNumberEventsByEnergyEMCal", 
					  500.0, 
					  0.0, 
					  20);            // FIX THIS!!! 
  
  /// Histograms
  hEtotTowerPreshower = (TH2D *)gROOT->FindObject("hEtotTowerPreshower");
  if (hEtotTowerPreshower) hEtotTowerPreshower->Reset();
  else
    hEtotTowerPreshower = new TH2D("hEtotTowerPreshower",
				   "hEtotTowerPreshower", 
				   Detector->GetEMCalNofTowersAxis(), 
				   0,
				   Detector->GetEMCalNofTowersAxis(),
				   Detector->GetEMCalNofTowersAxis(),
				   0,
				   Detector->GetEMCalNofTowersAxis());

  hNumberEventsByEnergyPreshower = (TH1D *)gROOT->FindObject("hNumberEventsByEnergyPreshower");
  if (hNumberEventsByEnergyPreshower) hNumberEventsByEnergyPreshower->Reset();
  else
    hNumberEventsByEnergyPreshower = new TH1D("hNumberEventsByEnergyPreshower",
					      "hNumberEventsByEnergyPreshower", 
					      100.0, 
					      0.0, 
					      2); 


  hEtotTowerHCal = (TH2D *)gROOT->FindObject("hEtotTowerHCal");
  if (hEtotTowerHCal) hEtotTowerHCal->Reset();
  else
    hEtotTowerHCal = new TH2D("hEtotTowerHCal",
			       "hEtotTowerHCal", 
			       Detector->GetHCalNofTowersAxis(), 
			       0,
			       Detector->GetHCalNofTowersAxis(),
			       Detector->GetHCalNofTowersAxis(),
			       0,
			       Detector->GetHCalNofTowersAxis());

  hNumberEventsByEnergyHCal = (TH1D *)gROOT->FindObject("hNumberEventsByEnergyHCal");
  if (hNumberEventsByEnergyHCal) hNumberEventsByEnergyHCal->Reset();
  else
    hNumberEventsByEnergyHCal = new TH1D("hNumberEventsByEnergyHCal",
					  "hNumberEventsByEnergyHCal", 
					  500.0, 
					  0.0, 
					  100);            // FIX THIS!!! 

}

//_____________________________________________________________________________
void sPHENIX_RootManager::RunAnalysis(){

  Double_t edeptotemcal, edeptotpreshower, edeptothcal;
  map<int,sPHENIX_CalorimeterHit*> EMCalTowerEdepCol = EMCalSD->GetEMCalTowerEdepCol();      // Too long to have the getter everywhere
  map<int,sPHENIX_CalorimeterHit*> HCalTowerEdepCol = HCalSD->GetHCalTowerEdepCol();        // Too long to have the getter everywhere
  map<int,sPHENIX_CalorimeterHit*> PreshowerTowerEdepCol = PreshowerSD->GetPreshowerTowerEdepCol(); 
  map<int,sPHENIX_CalorimeterHit*>::iterator iter1;
  map<int,sPHENIX_CalorimeterHit*>::iterator iter2;
  map<int,sPHENIX_CalorimeterHit*>::iterator iter3;

  edeptotemcal = 0;
  edeptotpreshower = 0;
  edeptothcal = 0;

  for(iter1 = EMCalTowerEdepCol.begin(); iter1 != EMCalTowerEdepCol.end(); iter1++){
    hEtotTowerEMCal->Fill((iter1->first)%Detector->GetEMCalNofTowersAxis(),
			  (iter1->first)/Detector->GetEMCalNofTowersAxis(),
			  iter1->second->GetEdepSensingMat());  // FIX THIS
    edeptotemcal += iter1->second->GetEdepSensingMat();
  }

  hNumberEventsByEnergyEMCal->Fill(edeptotemcal);

  for(iter2 = PreshowerTowerEdepCol.begin(); iter2 != PreshowerTowerEdepCol.end(); iter2++){
    hEtotTowerPreshower->Fill((iter2->first)%Detector->GetEMCalNofTowersAxis(),
			      (iter2->first)/Detector->GetEMCalNofTowersAxis(),
			      iter2->second->GetEdepSensingMat());  // FIX THIS
    edeptotpreshower += iter2->second->GetEdepSensingMat();
  }

  hNumberEventsByEnergyPreshower->Fill(edeptotpreshower);

  for(iter3 = HCalTowerEdepCol.begin(); iter3 != HCalTowerEdepCol.end(); iter3++){
    hEtotTowerHCal->Fill((iter3->first)%Detector->GetHCalNofTowersAxis(),
			  (iter3->first)/Detector->GetHCalNofTowersAxis(),
			  iter3->second->GetEdepSensingMat());  // FIX THIS
    edeptothcal += iter3->second->GetEdepSensingMat();
  }

  hNumberEventsByEnergyHCal->Fill(edeptothcal);


  // Clean this up!!!!!!!! 

  count++;
  
  if(NofEvents >= 100){
    if(count%(NofEvents/10) == 0){
      c2->cd(1);
      hEtotTowerEMCal->DrawCopy("colz");
      c2->cd(2);
      hNumberEventsByEnergyEMCal->DrawCopy();
      c2->cd(3);
      hEtotTowerPreshower->DrawCopy("colz");
      c2->cd(4);
      hNumberEventsByEnergyPreshower->DrawCopy();
      c2->cd(5);
      hEtotTowerHCal->DrawCopy("colz");
      c2->cd(6);
      hNumberEventsByEnergyHCal->DrawCopy();     
      c2->Update();
    }
  }
  else if(count == NofEvents){
    c2->cd(1);
    hEtotTowerEMCal->DrawCopy("colz");
    c2->cd(2);
    hNumberEventsByEnergyEMCal->DrawCopy();
    c2->cd(3);
    hEtotTowerPreshower->DrawCopy("colz");
    c2->cd(4);
    hNumberEventsByEnergyPreshower->DrawCopy();
    c2->cd(5);
    hEtotTowerHCal->DrawCopy("colz");
    c2->cd(6);
    hNumberEventsByEnergyHCal->DrawCopy();   
    c2->Update();
  }
  else{
    c2->cd(1);
    hEtotTowerEMCal->DrawCopy("colz");
    c2->cd(2);
    hNumberEventsByEnergyEMCal->DrawCopy();
    c2->cd(3);
    hEtotTowerPreshower->DrawCopy("colz");
    c2->cd(4);
    hNumberEventsByEnergyPreshower->DrawCopy();
    c2->cd(5);
    hEtotTowerHCal->DrawCopy("colz");
    c2->cd(6);
    hNumberEventsByEnergyHCal->DrawCopy();   
    c2->Update();
  }
}
